package com.yuzhihao.writejvm.attributes.runtimeva;

import com.yuzhihao.writejvm.clazz.ClassInfo;
import com.yuzhihao.writejvm.constant.ConstantUtf8Info;
import com.yuzhihao.writejvm.format.PrintFormat;
import com.yuzhihao.writejvm.read.Parse;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.log4j.Log4j2;

import java.io.DataInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * Each entry in the annotations table represents a single run-time visible annotation on a declaration.
 * <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.16">Annotation</a>
 *
 * @author yzh
 * @since 2021年12月11日14:02:51
 */
@Data
@Log4j2
@EqualsAndHashCode(callSuper = true)
public class Annotation extends ElementValue {

    private int type_index_u2 = 2;

    private int type_index;

    private int num_element_value_pairs_u2 = 2;

    private int num_element_value_pairs;

    private List<ElementValuePairs> evps = new ArrayList<>();

    private String constant;

    public Annotation() {
    }

    public Annotation(int tag) {
        super();
        super.setTag(tag);
    }

    @Override
    public void parse(DataInputStream dis, ClassInfo ci) {
        this.setCi(ci);
        try {
            this.type_index = Parse.byteToInt(this.type_index_u2, dis);
            this.num_element_value_pairs = Parse.byteToInt(this.num_element_value_pairs_u2, dis);

            int i = 0;
            while (i < this.num_element_value_pairs) {
                ElementValuePairs evp = new ElementValuePairs();
                evp.parse(dis, ci);
                this.evps.add(evp);
                i++;
            }
        } catch (IOException e) {
            log.error(e);
        }
    }

    public String getConstant() {
        if (Objects.nonNull(this.constant)) {
            return this.constant;
        }

        ConstantUtf8Info cui = (ConstantUtf8Info) this.getCi().getCp_info().getPools().get(String.valueOf(this.type_index));
        this.constant = cui.getConstant();
        return constant;
    }

    @Override
    public String print(String print, int index) {
        StringBuilder builder = new StringBuilder();

        builder.append(PrintFormat.EMPTY);
        builder.append(index)
                .append(PrintFormat.COLON)
                .append(PrintFormat.EMPTY)
                .append(PrintFormat.HASHTAG)
                .append(this.type_index)
                .append(PrintFormat.EMPTY)
                .append(PrintFormat.DOUBLE_SLASH)
                .append(PrintFormat.EMPTY)
                .append(this.getConstant())
                .append(System.lineSeparator())
        ;
        for (ElementValuePairs evp : this.evps) {
            builder.append(evp.print(print));
        }
        return builder.toString();
    }
}
